package com.tsfyun.scm.util;

import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.scm.dto.customer.ExpressStandardQuoteDTO;
import com.tsfyun.scm.dto.customer.ExpressStandardQuoteMemberDTO;
import com.tsfyun.scm.dto.customer.ExpressStandardQuotePlusDTO;
import com.tsfyun.scm.entity.customer.CustomerExpressQuote;
import com.tsfyun.scm.entity.customer.CustomerExpressQuoteMember;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @Description: 快递模式计算代理费工具类
 * @CreateDate: Created in 2020/10/22 16:26
 */
@Slf4j
public class ExpressQuoteUtil {

    /**
     * 根据重量计算代理费
     * @param weight
     * @param quote
     * @param members
     * @return
     */
    public static BigDecimal calculate(BigDecimal weight, CustomerExpressQuote quote, List<CustomerExpressQuoteMember> members) {
        log.info("原始重量【{}】",weight);
        //先四舍五入成2位小数再向上取整
        BigDecimal handleWeight = weight.setScale(2, BigDecimal.ROUND_HALF_UP);
        handleWeight = handleWeight.setScale(0,BigDecimal.ROUND_UP);
        log.info("重量四舍五入向上取整后为【{}】开始计算代理费",handleWeight);
        if(handleWeight.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("重量不能小于等于0");
        }
        BigDecimal sumFee = BigDecimal.ZERO;
        //先给标准报价明细按开始重量排序
        members = members.stream().sorted(Comparator.comparing(CustomerExpressQuoteMember::getStartWeight)).collect(Collectors.toList());
        BigDecimal finalHandleWeight = handleWeight;
        CustomerExpressQuoteMember customerExpressQuoteMember = members.stream().filter(member-> finalHandleWeight.compareTo(member.getStartWeight()) > 0
                && finalHandleWeight.compareTo(member.getEndWeight()) <= 0).findFirst().orElseThrow(()->new ServiceException("系统配置代理费报价信息有误"));
        sumFee = finalHandleWeight.multiply(customerExpressQuoteMember.getPrice()).add(customerExpressQuoteMember.getBasePrice()).setScale(2,BigDecimal.ROUND_HALF_UP);
        log.info("重量【{}】，计算出来的代理费【{}】",finalHandleWeight,sumFee);
        //判断是否设置了封顶
        if(Objects.equals(quote.getCapped(),Boolean.TRUE)
           && sumFee.compareTo(quote.getCappedFee()) == 1) {
            sumFee = quote.getCappedFee();
            log.info("重量【{}】，计算出来的代理费【{}】,超过封顶费用【{}】",weight,sumFee,quote.getCappedFee());
        }
        return sumFee;
    }

    public static void check(ExpressStandardQuotePlusDTO dto) {
        ExpressStandardQuoteDTO quoteDTO = dto.getQuote();
        List<ExpressStandardQuoteMemberDTO> quoteMembers = dto.getMembers();
        //如果选择了封顶则必须填写封顶金额
        if(Objects.equals(quoteDTO.getCapped(),Boolean.TRUE)
                && Objects.isNull(quoteDTO.getCappedFee())) {
            throw new ServiceException("封顶费用不能小于0");
        }
        //报价结束时间必须大于等于开始时间
        if(quoteDTO.getQuoteEndTime().compareTo(quoteDTO.getQuoteStartTime()) < 1) {
            throw new ServiceException("报价结束时间必须大于等于开始时间");
        }
        IntStream.range(0,quoteMembers.size()).forEach(idx->{
            ExpressStandardQuoteMemberDTO expressStandardQuoteMemberDTO = quoteMembers.get(idx);
            //第一条的起始重量必须等于0
            if(idx == 0 && expressStandardQuoteMemberDTO.getStartWeight().compareTo(BigDecimal.ZERO) != 0) {
                throw new ServiceException("第一条开始重量必须等于0");
            }
            //结束重量必须大于开始重量
            if(expressStandardQuoteMemberDTO.getEndWeight().compareTo(expressStandardQuoteMemberDTO.getStartWeight()) < 0) {
                throw new ServiceException(String.format("第%s行结束重量必须大于开始重量",idx + 1));
            }
            //当前行的开始重量必须等于上一行的结束重量
            if(idx > 0 && expressStandardQuoteMemberDTO.getStartWeight().compareTo(quoteMembers.get(idx - 1).getEndWeight()) != 0) {
                throw new ServiceException(String.format("第%s行开始重量必须等于第%s行结束重量",idx + 1, idx));
            }
            //最后一行的结束重量必须等于99999999
            if(idx == quoteMembers.size() - 1 && expressStandardQuoteMemberDTO.getEndWeight().compareTo(new BigDecimal("99999999")) != 0) {
                throw new ServiceException("最后一条结束重量必须等于99999999");
            }
        });
    }

}
